let {SyncHook} = require('tapable');
let fs = require('fs')
class Compiler {
    constructor(options) {
        this.options = options;
        this.hook = {
            run:new SyncHook(),
            done:new SyncHook()
        }
    }
    run(){
        let modules = [];
        let chunks = [];
        let files = [];
        this.hook.run.call();//触发run钩子的执行 context当前根目录
        //4： 确定入口：根据配置中的entry找到所有入口文件
        let entry = path.join(this.options.context,this.options.entry);
        //5.从入口文件出发，调用所有配置的Loader对模块进行编译，再找出该模块依赖的模块
        //再递归本步骤直到所有入口依赖的文件都经过了本步骤的处理
        //1.读取本模块的内容
        //let sum = (a,b) => a + b;let title = require('title')
        let entryContent = fs.readFileSync(entry,'utf-8');
        let entrySource =  babelLoader(entryContent);
        //模块module chunk代码块 file bundle文件的关系
        let entryModule = {id:entry,source:entrySource}
        modules.push(entryModule);
        //把入口模块的代码转成抽象AST，分析里面的import和require依赖
        let title = path.join(this.options.context,'./src/title.js');
        let titleContent = fs.readFileSync(title, 'utf-8');
        let titleSource = babelLoader(titleContent);
        //模块module chunk代码块 file bundle文件的关系
        let titleModule = { id: title, source: titleSource }
        modules.push(titleModule);
        //根据入口和模块之前的依赖关系，组成一个个包含多个代码块的Chunk
        let chunk = {name:'main',modules}
        chunk.push(chunk);
        //再把每个Chunk转成一个单独的文件加入到输出列表
        let file = {
            file:this.options.output.filename,
            source:`(funtion(){})({})`,
        }
        files.push(file);
        //再确定好输出内容后，根据配置确定输出的路径和文件名，把文件内容写入到文件系统
        let outputPath = path.join(this.options.output.path,this.options.output.filename);
        //在以上的过程中，Webpack会在特定的时间广播出特定的事件，插件在见通道感兴趣的事情后会执行特定的逻辑
        //并且插件可以调用Webpack提供的API改变Webpack的运行结果
        fs.writeFileSync(outputPath,file.source,'utf8');
        this.hooks.done.call();
    }
}

//1: 初始化参数：从配置文件和Shell(如：webpack--mode = development)语句中读取和合并参数，得到最终的参数
let options = require('./webpack.config');
//2: 开始编译：用上一步得到的参数初始化Compiler对象
let compiler = new Compiler(options);
//3： 加载所有配置的插件，执行对象的run 方法开始执行编译
if(options.plugins&&Array.isArray(options.plugins)){
    for(const plugin of options.plugins){
        plugin.apply(compiler);
    }
}
//4： 确定入口：根据配置中的entry找到所有入口文件
compiler.run();
//es6编译成es5
function babelLoader(source) {
    return `
    let sum = function(a,b) {return a + b};
    let title = require('./title')`
}